// Select.js

'use strict';

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {StyleSheet, View, TouchableOpacity, Image, Text, ScrollView} from 'react-native';

import Theme from 'teaset/themes/Theme';
import PullPicker from '../PullPicker/PullPicker';
import PopoverPicker from '../PopoverPicker/PopoverPicker';

export default class Select extends Component {
  
  static propTypes = {
    ...TouchableOpacity.propTypes,
    size: PropTypes.oneOf(['lg', 'md', 'sm']),
    value: PropTypes.any,
    valueStyle: Text.propTypes.style,
    items: PropTypes.array,
    getItemValue: PropTypes.func, //(item, index) 选择项值，item=items[index]，为空时直接使用item
    getItemText: PropTypes.func, //(item, index) return display text of item, item=items[index], use item when it's null
    pickerType: PropTypes.oneOf(['auto', 'pull', 'popover']),
    pickerTitle: PropTypes.string, //PullPicker only
    editable: PropTypes.bool,
    icon: PropTypes.oneOfType([PropTypes.element, PropTypes.shape({uri: PropTypes.string}), PropTypes.number, PropTypes.oneOf(['none', 'default'])]),
    iconTintColor: PropTypes.string, //set to null for no tint color
    placeholder: PropTypes.string,
    placeholderTextColor: PropTypes.string,
    onSelected: PropTypes.func, //(item, index)
  };

  static defaultProps = {
    ...TouchableOpacity.defaultProps,
    size: 'md',
    editable: true,
    icon: 'default',
    pickerType: 'auto',
  };

  measureInWindow(callback) {
    this.refs.selectView && this.refs.selectView.measureInWindow(callback);
  }

  measure(callback) {
    this.refs.selectView && this.refs.selectView.measure(callback);
  }

  get selectedIndex() {
    let {value, items, getItemValue} = this.props;
    if (items instanceof Array) {
      if (getItemValue) {
        for (let i = 0; i < items.length; ++i) {
          if (getItemValue(items[i], i) === value) return i;
        }
      } else {
        for (let i = 0; i < items.length; ++i) {
          if (items[i] === value) return i;
        }
      }
    }
    return -1;
  }

  get valueText() {
    let {value, items, getItemValue, getItemText} = this.props;
    let text = value;
    if (getItemText && items instanceof Array) {
      if (getItemValue) {
        for (let i = 0; i < items.length; ++i) {
          if (getItemValue(items[i], i) === value) {
            text = getItemText(items[i], i);
            break;
          }
        }
      } else {
        for (let i = 0; i < items.length; ++i) {
          if (items[i] === value) {
            text = getItemText(items[i], i);
            break;
          }
        }
      }
    }
    return (!text || React.isValidElement(text)) ? text : `${text}`;
  }

  buildStyle() {
    let {style, size, disabled} = this.props;

    let borderRadius, paddingTop, paddingBottom, paddingLeft, paddingRight, height;
    switch (size) {
      case 'lg':
        borderRadius = Theme.selectBorderRadiusLG;
        paddingTop = Theme.selectPaddingTopLG;
        paddingBottom = Theme.selectPaddingBottomLG;
        paddingLeft = Theme.selectPaddingLeftLG;
        paddingRight = Theme.selectPaddingRightLG;
        height = Theme.selectHeightLG;
        break;
      case 'sm':
        borderRadius = Theme.selectBorderRadiusSM;
        paddingTop = Theme.selectPaddingTopSM;
        paddingBottom = Theme.selectPaddingBottomSM;
        paddingLeft = Theme.selectPaddingLeftSM;
        paddingRight = Theme.selectPaddingRightSM;
        height = Theme.selectHeightSM;
        break;
      default:
        borderRadius = Theme.selectBorderRadiusMD;
        paddingTop = Theme.selectPaddingTopMD;
        paddingBottom = Theme.selectPaddingBottomMD;
        paddingLeft = Theme.selectPaddingLeftMD;
        paddingRight = Theme.selectPaddingRightMD;
        height = Theme.selectHeightMD;
    }
    style = [{
      backgroundColor: Theme.selectColor,
      borderColor: Theme.selectBorderColor,
      borderWidth: Theme.selectBorderWidth,
      borderRadius: borderRadius,
      paddingTop: paddingTop,
      paddingBottom: paddingBottom,
      paddingLeft: paddingLeft,
      paddingRight: paddingRight,
      height: height,
    }].concat(style).concat({flexDirection: 'row', alignItems: 'center'});
    if (disabled) style = style.concat({opacity: Theme.btnDisabledOpacity});

    return style;
  }

  showPullPicker() {
    let {pickerTitle, items, getItemText, onSelected} = this.props;
    PullPicker.show(
      pickerTitle,
      items,
      this.selectedIndex,
      onSelected,
      {getItemText}
    );
  }

  showPopoverPicker() {
    this.measure((x, y, width, height, pageX, pageY) => {
      let {items, getItemText, onSelected} = this.props;
      PopoverPicker.show(
        {x: pageX, y: pageY, width, height},
        items,
        this.selectedIndex,
        onSelected,
        {getItemText, align: 'end'}
      );
    });
  }

  showPicker() {
    switch (this.props.pickerType) {
      case 'pull':
        this.showPullPicker();
        break;
      case 'popover':
        this.showPopoverPicker();
        break;
      default:
        Theme.isPad ? this.showPopoverPicker() : this.showPullPicker();
        break;
    }
  }

  renderValue() {
    let {value, valueStyle, placeholder, placeholderTextColor, size} = this.props;

    let fontSize;
    switch (size) {
      case 'lg': fontSize = Theme.selectFontSizeLG; break;
      case 'sm': fontSize = Theme.selectFontSizeSM; break;
      default: fontSize = Theme.selectFontSizeMD;
    }
    valueStyle = [{
      color: Theme.selectTextColor,
      fontSize,
      flexGrow: 1,
      overflow: 'hidden',
    }].concat(valueStyle);

    if (!placeholderTextColor) placeholderTextColor = Theme.selectPlaceholderTextColor;

    let valueElement;
    if (value === null || value === undefined) {
      valueStyle = valueStyle.concat({color: placeholderTextColor});
      valueElement = <Text style={valueStyle} numberOfLines={1} allowFontScaling={false}>{placeholder}</Text>;
    } else {
      let valueText = this.valueText;
      if (React.isValidElement(valueText)) {
        valueElement = valueText;
      } else {
        valueElement = <Text style={valueStyle} numberOfLines={1} allowFontScaling={false}>{valueText}</Text>;
      }
    }
    return valueElement;
  }

  renderIcon() {
    let {size, icon, iconTintColor} = this.props;

    let iconSize;
    switch (size) {
      case 'lg': iconSize = Theme.selectIconSizeLG; break;
      case 'sm': iconSize = Theme.selectIconSizeSM; break;
      default: iconSize = Theme.selectIconSizeMD;
    }
    if (iconTintColor === undefined) iconTintColor = Theme.selectIconTintColor;

    let iconElement;
    if (icon === null || icon === undefined || icon === 'none') {
      iconElement = null;
    } else if (React.isValidElement(icon)) {
      iconElement = icon;
    } else {
      iconElement = (
        <Image
          style={{width: iconSize, height: iconSize, tintColor: iconTintColor}}
          source={icon === 'default' ? require('../../icons/select.png') : icon}
          />
      );
    }

    return (
      <View style={{position: 'absolute', top: 0, bottom: 0, right: 0, justifyContent: 'center'}}>
        {iconElement}
      </View>
    );
  }

  render() {
    let {style, children, disabled, size, value, valueStyle, items, getItemValue, getItemText, pickerType, pickerTitle, editable, icon, iconTintColor, placeholder, placeholderTextColor, onSelected, onPress, onLayout, ...others} = this.props;
    let ViewClass = disabled ? View : TouchableOpacity;
    return (
      <ViewClass
        style={this.buildStyle()}
        disabled={disabled || !editable}
        onPress={e => onPress ? onPress(e) : this.showPicker()}
        onLayout={e => {
          this.measure((x, y, width, height, pageX, pageY) => {
            this.popoverView && this.popoverView.updateFromBounds({x: pageX, y: pageY, width, height});
          });
          onLayout && onLayout(e);
        }}
        {...others}
        ref='selectView'
      >
        {this.renderValue()}
        {this.renderIcon()}
      </ViewClass>
    );
  }
}

